use crate::garden::vegetables::Asparagus; // 这句话
use rand::Rng;

use core::panic;
use std::collections::HashMap;
use std::fs::File;
use std::io::ErrorKind;
// use std::io;
// use std::cmp::Ordering;
// 上面两句可以写成下面一句
use std:: {cmp::Ordering, io};
// 如果我们要引入如下两个
// use std::io;
// use std::io::write;
use std::{self, write};
// 如果要引入一个包里边的所有内容，我们可以使用*

pub mod garden; // 这句话告诉编译器去包含src/graden.rs里边的代码，相当于引入
fn main() {
    let potatoes = crate::garden::vegetables::Potatoes{}; // 我们可以使用路径来引入
    println!("I'am growing {:#?}!", potatoes);
    let vegetables = Asparagus{}; // 同时我们使用use，让其他module的代码引入到自己的scope中使用，类似于Java的import
    println!("I'm growing {:#?}!", vegetables);

    let select_number = rand::thread_rng().gen_range(1..=100);

    let v: Vec<i32> = Vec::new();
    let v2 = vec![1, 2, 3]; // 带初始化的数据，可以使用vec!

    // 下面两个push方法没法执行，我们需要mut
    // v.push(1);
    // v2.push(2);
    let mut v3 : Vec<i32> = Vec::new();
    v3.push(4);

    let third = &v2[2]; // 我们使&和[]获取到的是数值
    println!("The third element is {}", third);
    let third2 = v2.get(2); // 使用get获取到的是Option类型，为了防止溢出
    // 在元素溢出的时候，[]获取到的会报错，get获取到的就是None
    let mut v = vec![1, 2, 3, 4, 5];
    let fir = &v[0];
    //v.push(6); // 在这里会报错，因为我们的0号元素被不可修改引用占用了，而push会造成内存分配，会移动之前的元素，但是之前的元素又不是mut的，因此会报错

    println!("The first element is {}", fir);

    // 遍历vec
    for i in &v {
        println!("{}", i);
    }

    for i in &mut v {
        *i += 50;
    }

    for i in &v {
        println!("{}", i);
    }

    enum SpreadSheetCell {
        Int(i32),
        Float(f64),
        Text(String),
    }

    let row = vec![
        SpreadSheetCell::Int(12),
        SpreadSheetCell::Float(3.14),
        SpreadSheetCell::Text(String::from("Hello World")),
    ];

    // 当vec超出scope之后，他也就被释放了
    {
        let v = vec![1, 2, 3, 4];

        // do stuff with v
    } // <- v goes out of scope and is freed here

    let mut s = String::new(); // 创建一个空的字符串
    // 我们也可以创建一个带数据的字符串
    let data = "Hello World";
    let s = data.to_string();
    // 也可以使用String::from()来创建
    let s = String::from("Hello World");

    let mut s = String::from("foo");
    let s2 = "bar";
    s.push_str(s2);
    println!("{}", s2);

    s.push('c'); // push 方法则是传递单个字符

    let s1 = String::from("Hello, ");
    let s2 = String::from("World");
    let s3 = s1 + &s2;
    // + 相当于 fn add(self, s: &str) -> String
    // 而 &String会强转成&str类型的，s1就没法用了，所有权给了s3

    let s4 = String::from("tic");
    let s5 = String::from("tac");
    let s6 = String::from("toe");
    let s7 = s4 + "_" + &s5 + "_" + &s6;
    
    
    let s4 = String::from("tic");
    let s5 = String::from("tac");
    let s6 = String::from("toe");
    let s7 = format!("{}-{}-{}", s4, s5, s6);
    // format的操作和println类似，但是他不会显示出来，另外format不会移动所有权，三个参数都还可以使用
    // 字符串不允许索引，s7[0]会报错
    //s7[0];
    let hello = "Здравствуйте";

    let s = &hello[0..4];
    println!("{}", s);

    for c in "Зд".chars() {
        println!("{}", c);
    }

    for b in "Зд".bytes() {
        println!("{}", b);
    }

    let mut scores = HashMap::new();
    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("yellow"), 50);

    let team_name = String::from("Blue");
    let score = scores.get(&team_name).copied().unwrap_or(0);
    // score会获取到Blue队的数据，get方法会获取到Option<&V>, 没这个数据的话会获取到None，而copied函数会把Option<&i32>变成Option<i32>.
    // 如果Blue的key没有对应的entry的时候，unwrap_or会把score设置为0
      
    for (key, value) in &scores {
        println!("{}, {}",key, value);
    }

    let key = String::from("Red");
    let value = 20;
    scores.insert(key, value);
    // 在这里，我们的key的value就归HashMap所有了，就没法再使用了
    // let a = key;

    scores.insert(String::from("Blue"), 20); // 如果我们插入一个重复的key那么value就会覆盖掉
    println!("{:?}", scores);

    scores.entry(String::from("Blue")).or_insert(40); // 这个表示如果Blue存在就不执行，如果不存在就插入

    // 如果我们需要更新我们的数据呢
    let text = "Hello world wonderful world";

    let mut map = HashMap::new();
    for word in text.split_whitespace() {
        let count = map.entry(word).or_insert(0);
        *count += 1;
    }
    println!("{:?}", map);

    //panic!("crash and burn"); // panic写法，我们可以添加RUST_BACKTRACE=1这个环境变量，打印更多递归信息
    // 也就是 `RUST_BACKTRACE=1 cargo run`

    // 不使用panic！macro来触发 panic
    let v = vec![1, 2, 3];
    // v[99];
    // Recoverable Errors with Result
    let greet_file_result = File::open("target/hello.txt");

    // 在文件不存在的情况下套娃去创建文件，就会出现match的嵌套形式
    let greet_file = match greet_file_result {
        Ok(file) => file,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("target/hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("Problem creating the file {:?}", e),
            },
            other_error => panic!("Problem opening the file {:?}", other_error)
        }
    };

    // 不嵌套的情况下去实现
    let greet_file2 = File::open("target/hello.txt").unwrap_or_else(|error| {
        if error.kind() == ErrorKind::NotFound {
            File::create("target/hello.txt").unwrap_or_else(|error| {
                panic!("Problem creating the file {:?}", error);
            })
        } else {
            panic!("Problem opening the file {:?}", error);
        }
    });

    // 简化版函数
    // unwrap()函数
    // 下面的一行代码如果这个文件不存在，就panic！错误，如果存在就该返回啥返回啥
    let greet_file3 = File::open("target/hello.txt").unwrap();

    // 下面这一行就是用expect里边的内容来代替panic！里边的内容
    let greet_file4 = File::open("target/hello.txt").expect("Failed to open the file");

    

}